home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / unifs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  19.3 KB  |  826 lines

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5.  */
  6.  
  7. /* a simple unified file system */
  8.  
  9. #include "mint.h"
  10.  
  11.  
  12. extern FILESYS bios_filesys, proc_filesys, pipe_filesys, shm_filesys;
  13.  
  14. static long    ARGS_ON_STACK uni_root    P_((int drv, fcookie *fc));
  15. static long    ARGS_ON_STACK uni_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  16. static long    ARGS_ON_STACK uni_getxattr    P_((fcookie *fc, XATTR *xattr));
  17. static long    ARGS_ON_STACK uni_chattr    P_((fcookie *fc, int attrib));
  18. static long    ARGS_ON_STACK uni_chown    P_((fcookie *fc, int uid, int gid));
  19. static long    ARGS_ON_STACK uni_chmode    P_((fcookie *fc, unsigned mode));
  20. static long    ARGS_ON_STACK uni_rmdir    P_((fcookie *dir, const char *name));
  21. static long    ARGS_ON_STACK uni_remove    P_((fcookie *dir, const char *name));
  22. static long    ARGS_ON_STACK uni_getname    P_((fcookie *root, fcookie *dir,
  23.                             char *pathname, int size));
  24. static long    ARGS_ON_STACK uni_rename    P_((fcookie *olddir, char *oldname,
  25.                     fcookie *newdir, const char *newname));
  26. static long    ARGS_ON_STACK uni_opendir    P_((DIR *dirh, int flags));
  27. static long    ARGS_ON_STACK uni_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  28. static long    ARGS_ON_STACK uni_rewinddir    P_((DIR *dirh));
  29. static long    ARGS_ON_STACK uni_closedir    P_((DIR *dirh));
  30. static long    ARGS_ON_STACK uni_pathconf    P_((fcookie *dir, int which));
  31. static long    ARGS_ON_STACK uni_dfree    P_((fcookie *dir, long *buf));
  32. static DEVDRV *    ARGS_ON_STACK uni_getdev    P_((fcookie *fc, long *devsp));
  33. static long    ARGS_ON_STACK uni_symlink    P_((fcookie *dir, const char *name, const char *to));
  34. static long    ARGS_ON_STACK uni_readlink    P_((fcookie *fc, char *buf, int buflen));
  35. static long    ARGS_ON_STACK uni_fscntl    P_((fcookie *dir, const char *name, int cmd, long arg));
  36.  
  37. FILESYS uni_filesys = {
  38.     (FILESYS *)0,
  39.     FS_LONGPATH,
  40.     uni_root,
  41.     uni_lookup, nocreat, uni_getdev, uni_getxattr,
  42.     uni_chattr, uni_chown, uni_chmode,
  43.     nomkdir, uni_rmdir, uni_remove, uni_getname, uni_rename,
  44.     uni_opendir, uni_readdir, uni_rewinddir, uni_closedir,
  45.     uni_pathconf, uni_dfree, nowritelabel, noreadlabel,
  46.     uni_symlink, uni_readlink, nohardlink, uni_fscntl, nodskchng
  47. };
  48.  
  49. /*
  50.  * structure that holds files
  51.  * if (mode & S_IFMT == S_IFDIR), then this is an alias for a drive:
  52.  *    "dev" holds the appropriate BIOS device number, and
  53.  *    "data" is meaningless
  54.  * if (mode & S_IFMT == S_IFLNK), then this is a symbolic link:
  55.  *    "dev" holds the user id of the owner, and
  56.  *    "data" points to the actual link data
  57.  */
  58.  
  59. typedef struct unifile {
  60.     char name[NAME_MAX+1];
  61.     ushort mode;
  62.     ushort dev;
  63.     FILESYS *fs;
  64.     void *data;
  65.     struct unifile *next;
  66.     short cdate, ctime;
  67. } UNIFILE;
  68.  
  69. static UNIFILE u_drvs[UNI_NUM_DRVS];
  70. static UNIFILE *u_root = 0;
  71.  
  72. static long    do_ulookup    P_((fcookie *, const char *, fcookie *, UNIFILE **));
  73.  
  74. FILESYS *
  75. get_filesys (dev)
  76.      int dev;
  77. {
  78.   UNIFILE *u;
  79.  
  80.   for (u = u_root; u; u = u->next)
  81.     if (u->dev == dev)
  82.       return u->fs;
  83.   return (FILESYS *) 0L;
  84. }
  85.  
  86. void
  87. unifs_init()
  88. {
  89.     UNIFILE *u = u_drvs;
  90.     int i;
  91.  
  92.     u_root = u;
  93.     for (i = 0; i < UNI_NUM_DRVS; i++,u++) {
  94.         u->next = u+1;
  95.         u->mode = S_IFDIR|DEFAULT_DIRMODE;
  96.         u->dev = i;
  97.         u->cdate = datestamp;
  98.         u->ctime = timestamp;
  99.         if (i == PROCDRV) {
  100.             strcpy(u->name, "proc");
  101.             u->fs = &proc_filesys;
  102.         } else if (i == PIPEDRV) {
  103.             strcpy(u->name, "pipe");
  104.             u->fs = &pipe_filesys;
  105.         } else if (i == BIOSDRV) {
  106.             strcpy(u->name, "dev");
  107.             u->fs = &bios_filesys;
  108.         } else if (i == UNIDRV) {
  109.             (u-1)->next = u->next;    /* skip this drive */
  110.         } else if (i == SHMDRV) {
  111.             strcpy(u->name, "shm");
  112.             u->fs = &shm_filesys;
  113.         } else {
  114.             u->name[0] = i + 'a';
  115.             u->name[1] = 0;
  116.             u->fs = 0;
  117.         }
  118.     }
  119.     --u;    /* oops, we went too far */
  120.     u->next = 0;
  121. }
  122.  
  123. static long ARGS_ON_STACK 
  124. uni_root(drv, fc)
  125.     int drv;
  126.     fcookie *fc;
  127. {
  128.     if (drv == UNIDRV) {
  129.         fc->fs = &uni_filesys;
  130.         fc->dev = drv;
  131.         fc->index = 0L;
  132.         return 0;
  133.     }
  134.     fc->fs = 0;
  135.     return EINTRN;
  136. }
  137.  
  138. static long ARGS_ON_STACK 
  139. uni_lookup(dir, name, fc)
  140.     fcookie *dir;
  141.     const char *name;
  142.     fcookie *fc;
  143. {
  144.     return do_ulookup(dir, name, fc, (UNIFILE **)0);
  145. }
  146.  
  147. /* worker function for uni_lookup; can also return the UNIFILE
  148.  * pointer for the root directory
  149.  */
  150. static long
  151. do_ulookup(dir, name, fc, up)
  152.     fcookie *dir;
  153.     const char *name;
  154.     fcookie *fc;
  155.     UNIFILE **up;
  156. {
  157.     UNIFILE *u;
  158.     long drvs;
  159.     FILESYS *fs;
  160.     fcookie *tmp;
  161.     extern long dosdrvs;
  162.  
  163.     TRACE(("uni_lookup(%s)", name));
  164.  
  165.     if (dir->index != 0) {
  166.         DEBUG(("uni_lookup: bad directory"));
  167.         return EPTHNF;
  168.     }
  169. /* special case: an empty name in a directory means that directory */
  170. /* so do "." and ".." */
  171.  
  172.     if (!*name || !strcmp(name, ".") || !strcmp(name, "..")) {
  173.         dup_cookie(fc, dir);
  174.         return 0;
  175.     }
  176.     drvs = drvmap() | dosdrvs | PSEUDODRVS;
  177. /*
  178.  * OK, check the list of aliases and special directories
  179.  */
  180.     for (u = u_root; u; u = u->next) {
  181.         if (!strnicmp(name, u->name, NAME_MAX)) {
  182.             if ( (u->mode & S_IFMT) == S_IFDIR ) {
  183.                 if (u->dev >= NUM_DRIVES) {
  184.                     fs = u->fs;
  185.                     if (up) *up = u;
  186.                     return (*fs->root)(u->dev,fc);
  187.                 }
  188.                 if ((drvs & (1L << u->dev)) == 0)
  189.                     return EPTHNF;
  190.                 tmp = &curproc->root[u->dev];
  191.                 if (!tmp->fs) {        /* drive changed? */
  192.                     changedrv(tmp->dev);
  193.                     tmp = &curproc->root[u->dev];
  194.                     if (!tmp->fs)
  195.                         return EPTHNF;
  196.                 }
  197.                 dup_cookie(fc, tmp);
  198.             } else {        /* a symbolic link */
  199.                 fc->fs = &uni_filesys;
  200.                 fc->dev = UNIDRV;
  201.                 fc->index = (long)u;
  202.             }
  203.             if (up) *up = u;
  204.             return 0;
  205.         }
  206.     }
  207.     DEBUG(("uni_lookup: name (%s) not found", name));
  208.     return EFILNF;
  209. }
  210.  
  211. static long ARGS_ON_STACK 
  212. uni_getxattr(fc, xattr)
  213.     fcookie *fc;
  214.     XATTR *xattr;
  215. {
  216.     UNIFILE *u = (UNIFILE *)fc->index;
  217.  
  218.     if (fc->fs != &uni_filesys) {
  219.         ALERT("ERROR: wrong file system getxattr called");
  220.         return EINTRN;
  221.     }
  222.  
  223.     xattr->index = fc->index;
  224.     xattr->dev = xattr->rdev = fc->dev;
  225.     xattr->nlink = 1;
  226.     xattr->blksize = 1;
  227.  
  228. /* If "u" is null, then we have the root directory, otherwise
  229.  * we use the UNIFILE structure to get the info about it
  230.  */
  231.     if (!u || ( (u->mode & S_IFMT) == S_IFDIR )) {
  232.         xattr->uid = xattr->gid = 0;
  233.         xattr->size = xattr->nblocks = 0;
  234.         xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
  235.         xattr->attr = FA_DIR;
  236.     } else {
  237.         xattr->uid = u->dev;
  238.         xattr->gid = 0;
  239.         xattr->size = xattr->nblocks = strlen(u->data) + 1;
  240.         xattr->mode = u->mode;
  241.         xattr->attr = 0;
  242.     }
  243.     xattr->mtime = xattr->atime = xattr->ctime = u->ctime;
  244.     xattr->mdate = xattr->adate = xattr->cdate = u->cdate;
  245.     return 0;
  246. }
  247.  
  248. static long ARGS_ON_STACK 
  249. uni_chattr(dir, attrib)
  250.     fcookie *dir;
  251.     int attrib;
  252. {
  253.     UNUSED(dir); UNUSED(attrib);
  254.     return EACCDN;
  255. }
  256.  
  257. static long ARGS_ON_STACK 
  258. uni_chown(dir, uid, gid)
  259.     fcookie *dir;
  260.     int uid, gid;
  261. {
  262.     UNUSED(dir); UNUSED(uid);
  263.     UNUSED(gid);
  264.     return EINVFN;
  265. }
  266.  
  267. static long ARGS_ON_STACK 
  268. uni_chmode(dir, mode)
  269.     fcookie *dir;
  270.     unsigned mode;
  271. {
  272.     UNUSED(dir);
  273.     UNUSED(mode);
  274.     return EINVFN;
  275. }
  276.  
  277. static long ARGS_ON_STACK 
  278. uni_rmdir(dir, name)
  279.     fcookie *dir;
  280.     const char *name;
  281. {
  282.     long r;
  283.  
  284.     r = uni_remove(dir, name);
  285.     if (r == EFILNF) r = EPTHNF;
  286.     return r;
  287. }
  288.  
  289. static long ARGS_ON_STACK 
  290. uni_remove(dir, name)
  291.     fcookie *dir;
  292.     const char *name;
  293. {
  294.     UNIFILE *u, *lastu;
  295.  
  296.     UNUSED(dir);
  297.  
  298.     lastu = 0;
  299.     u = u_root;
  300.     while (u) {
  301.         if (!strnicmp(u->name, name, NAME_MAX)) {
  302.             if ( (u->mode & S_IFMT) != S_IFLNK ) return EFILNF;
  303.             if (curproc->euid && (u->dev != curproc->euid))
  304.                 return EACCDN;
  305.             kfree(u->data);
  306.             if (lastu)
  307.                 lastu->next = u->next;
  308.             else
  309.                 u_root = u->next;
  310.             kfree(u);
  311.             return 0;
  312.         }
  313.         lastu = u;
  314.         u = u->next;
  315.     }
  316.     return EFILNF;
  317. }
  318.  
  319. static long ARGS_ON_STACK 
  320. uni_getname(root, dir, pathname, size)
  321.     fcookie *root, *dir; char *pathname;
  322.     int size;
  323. {
  324.     FILESYS *fs;
  325.     UNIFILE *u;
  326.     char *n;
  327.     fcookie relto;
  328.     char tmppath[PATH_MAX];
  329.     long r;
  330.  
  331.     UNUSED(root);
  332.  
  333.     if (size <= 0) return ERANGE;
  334.  
  335.     fs = dir->fs;
  336.     if (dir->dev == UNIDRV) {
  337.         *pathname = 0;
  338.         return 0;
  339.     }
  340.  
  341.     for (u = u_root; u; u = u->next) {
  342.         if (dir->dev == u->dev && (u->mode & S_IFMT) == S_IFDIR) {
  343.             *pathname++ = '\\';
  344.             if (--size <= 0) return ERANGE;
  345.             for (n = u->name; *n; ) {
  346.                 *pathname++ = *n++;
  347.                 if (--size <= 0) return ERANGE;
  348.             }
  349.             break;
  350.         }
  351.     }
  352.  
  353.     if (!u) {
  354.         ALERT("unifs: couldn't match a drive with a directory");
  355.         return EPTHNF;
  356.     }
  357.  
  358.     if (dir->dev >= NUM_DRIVES) {
  359.         if ((*fs->root)(dir->dev, &relto) == 0) {
  360.             if (!(fs->fsflags & FS_LONGPATH)) {
  361.                 r = (*fs->getname)(&relto, dir, tmppath, PATH_MAX);
  362.                 release_cookie(&relto);
  363.                 if (r) {
  364.                     return r;
  365.                 }
  366.                 if (strlen(tmppath) < size) {
  367.                     strcpy(pathname, tmppath);
  368.                     return 0;
  369.                 } else {
  370.                     return ERANGE;
  371.                 }
  372.             }
  373.             r = (*fs->getname)(&relto, dir, pathname, size);
  374.             release_cookie(&relto);
  375.             return r;
  376.         } else {
  377.             *pathname = 0;
  378.             return EINTRN;
  379.         }
  380.     }
  381.  
  382.     if (curproc->root[dir->dev].fs != fs) {
  383.         ALERT("unifs: drive's file system doesn't match directory's");
  384.         return EINTRN;
  385.     }
  386.  
  387.     if (!fs) {
  388.         *pathname = 0;
  389.         return 0;
  390.     }
  391.     if (!(fs->fsflags & FS_LONGPATH)) {
  392.         r = (*fs->getname)(&curproc->root[dir->dev], dir, tmppath, PATH_MAX);
  393.         if (r) return r;
  394.         if (strlen(tmppath) < size) {
  395.             strcpy(pathname, tmppath);
  396.             return 0;
  397.         } else {
  398.             return ERANGE;
  399.         }
  400.     }
  401.     return (*fs->getname)(&curproc->root[dir->dev], dir, pathname, size);
  402. }
  403.  
  404. static long ARGS_ON_STACK 
  405. uni_rename(olddir, oldname, newdir, newname)
  406.     fcookie *olddir;
  407.     char *oldname;
  408.     fcookie *newdir;
  409.     const char *newname;
  410. {
  411.     UNIFILE *u;
  412.     fcookie fc;
  413.     long r;
  414.  
  415.     UNUSED(olddir);
  416.  
  417.     for (u = u_root; u; u = u->next) {
  418.         if (!strnicmp(u->name, oldname, NAME_MAX))
  419.             break;
  420.     }
  421.  
  422.     if (!u) {
  423.         DEBUG(("uni_rename: old file not found"));
  424.         return EFILNF;
  425.     }
  426.  
  427. /* the new name is not allowed to exist! */
  428.     r = uni_lookup(newdir, newname, &fc);
  429.     if (r == 0)
  430.         release_cookie(&fc);
  431.  
  432.     if (r != EFILNF) {
  433.         DEBUG(("uni_rename: error %ld", r));
  434.         return (r == 0) ? EACCDN : r;
  435.     }
  436.  
  437.     (void)strncpy(u->name, newname, NAME_MAX);
  438.     return 0;
  439. }
  440.  
  441. static long ARGS_ON_STACK 
  442. uni_opendir(dirh, flags)
  443.     DIR *dirh;
  444.     int flags;
  445. {
  446.     UNUSED(flags);
  447.  
  448.     if (dirh->fc.index != 0) {
  449.         DEBUG(("uni_opendir: bad directory"));
  450.         return EPTHNF;
  451.     }
  452.     dirh->index = 0;
  453.     return 0;
  454. }
  455.  
  456.  
  457. static long ARGS_ON_STACK 
  458. uni_readdir(dirh, name, namelen, fc)
  459.     DIR *dirh;
  460.     char *name;
  461.     int namelen;
  462.     fcookie *fc;
  463. {
  464.     long map;
  465.     char *dirname;
  466.     int i;
  467.     int giveindex = (dirh->flags == 0);
  468.     UNIFILE *u;
  469.     long index;
  470.     extern long dosdrvs;
  471.     long r;
  472.  
  473.     map = dosdrvs | drvmap() | PSEUDODRVS;
  474.     i = dirh->index++;
  475.     u = u_root;
  476.     while (i > 0) {
  477.         --i;
  478.         u = u->next;
  479.         if (!u)
  480.             break;
  481.     }
  482. tryagain:
  483.     if (!u) return ENMFIL;
  484.  
  485.     dirname = u->name;
  486.     index = (long)u;
  487.     if ( (u->mode & S_IFMT) == S_IFDIR ) {
  488. /* make sure the drive really exists */
  489.         if ( u->dev >= NUM_DRIVES) {
  490.             r = (*u->fs->root)(u->dev,fc);
  491.             if (r) {
  492.             fc->fs = &uni_filesys;
  493.             fc->index = 0;
  494.             fc->dev = u->dev;
  495.             }
  496.         } else {
  497.             if ((map & (1L << u->dev)) == 0 ) {
  498.             dirh->index++;
  499.             u = u->next;
  500.             goto tryagain;
  501.             }
  502.             dup_cookie(fc, &curproc->root[u->dev]);
  503.             if (!fc->fs) {    /* drive not yet initialized */
  504.         /* use default attributes */
  505.             fc->fs = &uni_filesys;
  506.             fc->index = 0;
  507.             fc->dev = u->dev;
  508.             }
  509.         }
  510.     } else {        /* a symbolic link */
  511.         fc->fs = &uni_filesys;
  512.         fc->dev = UNIDRV;
  513.         fc->index = (long)u;
  514.     }
  515.  
  516.     if (giveindex) {
  517.         namelen -= (int)sizeof(long);
  518.         if (namelen <= 0) {
  519.             release_cookie(fc);
  520.             return ERANGE;
  521.         }
  522.         *((long *)name) = index;
  523.         name += sizeof(long);
  524.     }
  525.     strncpy(name, dirname, namelen-1);
  526.     if (strlen(name) < strlen(dirname)) {
  527.         release_cookie(fc);
  528.         return ENAMETOOLONG;
  529.     }
  530.     return 0;
  531. }
  532.  
  533. static long ARGS_ON_STACK 
  534. uni_rewinddir(dirh)
  535.     DIR *dirh;
  536. {
  537.     dirh->index = 0;
  538.     return 0;
  539. }
  540.  
  541. static long ARGS_ON_STACK 
  542. uni_closedir(dirh)
  543.     DIR *dirh;
  544. {
  545.     UNUSED(dirh);
  546.     return 0;
  547. }
  548.  
  549. static long ARGS_ON_STACK 
  550. uni_pathconf(dir, which)
  551.     fcookie *dir;
  552.     int which;
  553. {
  554.     UNUSED(dir);
  555.  
  556.     switch(which) {
  557.     case -1:
  558.         return DP_MAXREQ;
  559.     case DP_IOPEN:
  560.         return 0;        /* no files to open */
  561.     case DP_MAXLINKS:
  562.         return 1;        /* no hard links available */
  563.     case DP_PATHMAX:
  564.         return PATH_MAX;
  565.     case DP_NAMEMAX:
  566.         return NAME_MAX;
  567.     case DP_ATOMIC:
  568.         return 1;        /* no atomic writes */
  569.     case DP_TRUNC:
  570.         return DP_AUTOTRUNC;
  571.     case DP_CASE:
  572.         return DP_CASEINSENS;
  573.     case DP_MODEATTR:
  574.         return DP_FT_DIR|DP_FT_LNK;
  575.     case DP_XATTRFIELDS:
  576.         return DP_INDEX|DP_DEV|DP_NLINK|DP_SIZE;
  577.     default:
  578.         return EINVFN;
  579.     }
  580. }
  581.  
  582. static long ARGS_ON_STACK 
  583. uni_dfree(dir, buf)
  584.     fcookie *dir;
  585.     long *buf;
  586. {
  587.     UNUSED(dir);
  588.  
  589.     buf[0] = 0;    /* number of free clusters */
  590.     buf[1] = 0;    /* total number of clusters */
  591.     buf[2] = 1;    /* sector size (bytes) */
  592.     buf[3] = 1;    /* cluster size (sectors) */
  593.     return 0;
  594. }
  595.  
  596. static DEVDRV * ARGS_ON_STACK 
  597. uni_getdev(fc, devsp)
  598.     fcookie *fc;
  599.     long *devsp;
  600. {
  601.     UNUSED(fc);
  602.  
  603.     *devsp = EACCDN;
  604.     return 0;
  605. }
  606.  
  607. static long ARGS_ON_STACK 
  608. uni_symlink(dir, name, to)
  609.     fcookie *dir;
  610.     const char *name;
  611.     const char *to;
  612. {
  613.     UNIFILE *u;
  614.     fcookie fc;
  615.     long r;
  616.  
  617.     r = uni_lookup(dir, name, &fc);
  618.     if (r == 0) {
  619.         release_cookie(&fc);
  620.         return EACCDN;    /* file already exists */
  621.     }
  622.     if (r != EFILNF) return r;    /* some other error */
  623.  
  624.     if (curproc->egid)
  625.         return EACCDN;    /* only members of admin group may do that */
  626.  
  627.     u = kmalloc(SIZEOF(UNIFILE));
  628.     if (!u) return EACCDN;
  629.  
  630.     strncpy(u->name, name, NAME_MAX);
  631.     u->name[NAME_MAX] = 0;
  632.  
  633.     u->data = kmalloc((long)strlen(to)+1);
  634.     if (!u->data) {
  635.         kfree(u);
  636.         return EACCDN;
  637.     }
  638.     strcpy(u->data, to);
  639.     u->mode = S_IFLNK | DEFAULT_DIRMODE;
  640.     u->dev = curproc->euid;
  641.     u->next = u_root;
  642.     u->fs = &uni_filesys;
  643.     u->cdate = datestamp;
  644.     u->ctime = timestamp;
  645.     u_root = u;
  646.     return 0;
  647. }
  648.  
  649. static long ARGS_ON_STACK 
  650. uni_readlink(fc, buf, buflen)
  651.     fcookie *fc;
  652.     char *buf;
  653.     int buflen;
  654. {
  655.     UNIFILE *u;
  656.  
  657.     u = (UNIFILE *)fc->index;
  658.     assert(u);
  659.     assert((u->mode & S_IFMT) == S_IFLNK);
  660.     assert(u->data);
  661.     strncpy(buf, u->data, buflen);
  662.     if (strlen(u->data) >= buflen)
  663.         return ENAMETOOLONG;
  664.     return 0;
  665. }
  666.  
  667.  
  668.  
  669.  
  670. /* uk: use these Dcntl's to install a new filesystem which is only visible
  671.  *     on drive u:
  672.  *
  673.  *     FS_INSTALL:   let the kernel know about the file system; it does NOT
  674.  *                   get a device number.
  675.  *     FS_MOUNT:     use Dcntl(FS_MOUNT, "u:\\foo", &descr) to make a directory
  676.  *                   foo where the filesytem resides in; the file system now
  677.  *                   gets its device number which is also written into the
  678.  *                   dev_no field of the fs_descr structure.
  679.  *     FS_UNMOUNT:   remove a file system's directory; this call closes all
  680.  *                   open files, directory searches and directories on this
  681.  *                   device. Make sure that the FS will not recognise any
  682.  *                   accesses to this device, as fs->root will be called
  683.  *                   during the reinitalisation!
  684.  *     FS_UNINSTALL: remove a file system completely from the kernel list,
  685.  *                   but that will only be possible if there is no directory
  686.  *                   associated with this file system.
  687.  *                   This function allows it to write file systems as demons
  688.  *                   which stay in memory only as long as needed.
  689.  *
  690.  * BUG: it is not possible yet to lock such a filesystem.
  691.  */
  692.  
  693. /* here we start with gemdos only file system device numbers */
  694. static curr_dev_no = 0x100;
  695.  
  696.  
  697.  
  698. static long ARGS_ON_STACK
  699. uni_fscntl(dir, name, cmd, arg)
  700.     fcookie *dir;
  701.     const char *name;
  702.     int cmd;
  703.     long arg;
  704. {
  705.     fcookie fc;
  706.     long r;
  707.  
  708.     extern struct kerinfo kernelinfo;
  709.     extern FILESYS *active_fs;
  710.  
  711.     if (cmd == (int)FS_INSTALL) { /* install a new filesystem */
  712.         struct fs_descr *d = (struct fs_descr*)arg;
  713.         FILESYS *fs;
  714.  
  715.     /* check if FS is installed already */
  716.         for (fs = active_fs;  fs;  fs = fs->next)
  717.             if (d->file_system == fs)  return 0L;
  718.     /* include new file system into chain of file systems */
  719.         d->file_system->next = active_fs;
  720.         active_fs = d->file_system;
  721.         return (long)&kernelinfo;  /* return pointer to kernel info as OK */
  722.     } else if (cmd == (int)FS_MOUNT) {  /* install a new gemdos-only device for this FS */
  723.         struct fs_descr *d = (struct fs_descr*)arg;
  724.         FILESYS *fs;
  725.         UNIFILE *u;
  726.  
  727.     /* first check for existing names */
  728.         r = uni_lookup(dir, name, &fc);
  729.         if (r == 0) {
  730.             release_cookie(&fc);
  731.             return EACCDN;   /* name exists already */
  732.         }
  733.         if (r != EFILNF) return r; /* some other error */
  734.         if (!d) return EACCDN;
  735.         if (!d->file_system) return EACCDN;
  736.     /* check if FS is installed */
  737.         for (fs = active_fs;  fs;  fs = fs->next)
  738.             if (d->file_system == fs)  break;
  739.         if (!fs) return EACCDN;  /* not installed, so return an error */
  740.         u = kmalloc(SIZEOF(UNIFILE));
  741.         if (!u) return EACCDN;
  742.         strncpy(u->name, name, NAME_MAX);
  743.         u->name[NAME_MAX] = 0;
  744.         u->mode = S_IFDIR|DEFAULT_DIRMODE;
  745.         u->data = 0;
  746.         u->fs = d->file_system;
  747.     /* now get the file system its own device number */
  748.         u->dev = d->dev_no = curr_dev_no++;
  749.     /* chain new entry into unifile list */
  750.         u->next = u_root;
  751.         u_root = u;
  752.         return (long)u->dev;
  753.     } else if (cmd == (int)FS_UNMOUNT) {  /* remove a file system's directory */
  754.         struct fs_descr *d = (struct fs_descr*)arg;
  755.         FILESYS *fs;
  756.         UNIFILE *u;
  757.  
  758.     /* first check that directory exists */
  759.     /* use special uni_lookup mode to get the unifile entry */
  760.         r = do_ulookup(dir, name, &fc, &u);
  761.         if (r != 0)  return EFILNF;   /* name does not exist */
  762.         if (!d) return EFILNF;
  763.         if (!d->file_system) return EFILNF;
  764.         if (d->file_system != fc.fs)
  765.             return EFILNF;  /* not the right name! */
  766.         release_cookie(&fc);
  767.  
  768.         if (!u || (u->fs != d->file_system))
  769.             return EFILNF;
  770.     /* check if FS is installed */
  771.         for (fs = active_fs;  fs;  fs = fs->next)
  772.             if (d->file_system == fs)  break;
  773.         if (!fs) return EACCDN;  /* not installed, so return an error */
  774.  
  775.     /* here comes the difficult part: we have to close all files on that
  776.      * device, so we have to call changedrv(). The file system driver
  777.      * has to make sure that further calls to fs.root() with this device
  778.      * number will fail!
  779.      *
  780.      * Kludge: mark the directory as a link, so uni_remove will remove it.
  781.      */
  782.         changedrv(u->dev);
  783.         u->mode &= ~S_IFMT;
  784.         u->mode |= S_IFLNK;
  785.         return uni_remove(dir, name);
  786.     } else if (cmd == (int)FS_UNINSTALL) {    /* remove file system from kernel list */
  787.         struct fs_descr *d = (struct fs_descr*)arg;
  788.         FILESYS *fs, *last_fs;
  789.         UNIFILE *u;
  790.  
  791.     /* first check if there are any files or directories associated with
  792.      * this file system
  793.      */
  794.         for (u = u_root;  u;  u = u->next)
  795.             if (u->fs == d->file_system)
  796.                 return EACCDN;   /* we cannot remove it before unmount */
  797.         last_fs = 0;
  798.         fs = active_fs;
  799.         while (fs)  {   /* go through the list and remove the file system */
  800.             if (fs == d->file_system)  {
  801.                 if (last_fs)
  802.                     last_fs->next = fs->next;
  803.                 else
  804.                     active_fs = fs->next;
  805.                 d->file_system->next = 0;
  806.                 return 0;
  807.             }
  808.             last_fs = fs;
  809.             fs = fs->next;
  810.         }
  811.         return EFILNF;
  812.     } else {
  813.     /* see if we should just pass this along to another file system */
  814.         r = uni_lookup(dir, name, &fc);
  815.         if (r == 0) {
  816.             if (fc.fs != &uni_filesys) {
  817.                 r = (*fc.fs->fscntl)(&fc, ".", cmd, arg);
  818.                 release_cookie(&fc);
  819.                 return r;
  820.             }
  821.             release_cookie(&fc);
  822.         }
  823.     }
  824.     return EINVFN;
  825. }
  826.